package com.dcy.generate;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.dialect.Props;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.TemplateType;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.dcy.common.base.controller.DcyBaseController;
import com.dcy.common.base.mapper.DcyBaseMapper;
import com.dcy.common.base.service.DcyBaseService;
import com.dcy.generate.model.GenerModel;
import com.dcy.generate.model.PackageModel;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.Arrays;
import java.util.Map;

/**
 * @Author：dcy
 * @Description: 基础版代码生成器
 * @Date: 2020/7/22 10:25
 */
@Slf4j
public class DcyGenerator {

    public static final String CREATE_IN_VO = "CreateInVO.java";
    public static final String UPDATE_IN_VO = "UpdateInVO.java";
    public static final String SEARCH_IN_VO = "SearchInVO.java";
    public static final String LIST_OUT_VO = "ListOutVO.java";
    public static final String CONVERT = "Convert.java";
    public static final String DAO = "Dao.java";
    public static final String VUE = "-manage.vue";
    public static final String VUE_JS = ".js";

    /**
     * RUN THIS
     */
    public static void main(String[] args) {
        final GenerModel generModel = Props.getProp("db.properties", CharsetUtil.UTF_8).toBean(GenerModel.class, "db");
        final PackageModel packageModel = Props.getProp("package.properties", CharsetUtil.UTF_8).toBean(PackageModel.class, "package");

        FastAutoGenerator.create(generModel.getUrl(), generModel.getUsername(), generModel.getPassword())
                .globalConfig(builder -> {
                    builder.author("dcy")
                            // 生成文件的输出目录
                            .outputDir(generModel.getPack())
                            // 是否打开输出目录
                            .disableOpenDir()
                            // 时间类型对应策略
                            .dateType(DateType.ONLY_DATE);
                })
                .packageConfig(builder -> {
                    builder.parent(packageModel.getParent())
                            .controller(packageModel.getController())
                            .entity(packageModel.getEntity())
                            .serviceImpl(packageModel.getServiceImpl())
                            .mapper(packageModel.getMapper())
                            .xml(packageModel.getXml());
                })
                .strategyConfig(builder -> {
                    builder
                            .addTablePrefix(generModel.getPrefix())
                            .addInclude(Arrays.asList(generModel.getTableName().split(",")))

                            .entityBuilder()
                            .naming(NamingStrategy.underline_to_camel)
                            .enableLombok()
                            .enableChainModel()
                            .fileOverride()

                            .mapperBuilder()
                            .superClass(DcyBaseMapper.class)
                            .enableBaseColumnList()
                            .enableBaseResultMap()
                            .fileOverride()


                            .serviceBuilder()
                            .superServiceImplClass(DcyBaseService.class)
                            .formatServiceImplFileName("%sService")
                            .fileOverride()


                            .controllerBuilder()
                            .superClass(DcyBaseController.class)
                            .enableRestStyle()
                            .enableHyphenStyle()
                            .fileOverride();

                })
                .templateConfig(builder -> {
                    builder.disable(TemplateType.SERVICE)
                            .controller("/simple/controller.java")
                            .serviceImpl("/simple/serviceImpl.java")
                            .xml("/simple/mapper.xml");
                })
                .templateEngine(new FreemarkerTemplateEngine() {
                    @Override
                    protected void outputCustomFile(@NotNull Map<String, String> customFile, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
                        String entityName = tableInfo.getEntityName();
                        String otherPath = getPathInfo(OutputFile.other);
                        customFile.forEach((key, value) -> {
                            String fileName = String.format((otherPath + File.separator + entityName + File.separator + "%s"), key);
                            if (CREATE_IN_VO.equals(key) || UPDATE_IN_VO.equals(key) || SEARCH_IN_VO.equals(key)) {
                                fileName = String.format((MapUtil.getStr(objectMap, "inputDtoUrl") + entityName + "%s"), key);
                            } else if (LIST_OUT_VO.equals(key)) {
                                fileName = String.format((MapUtil.getStr(objectMap, "outputDtoUrl") + entityName + "%s"), key);
                            } else if (CONVERT.equals(key)) {
                                fileName = String.format((MapUtil.getStr(objectMap, "dtoMapperUrl") + entityName + "%s"), key);
                            } else if (DAO.equals(key)) {
                                fileName = String.format((MapUtil.getStr(objectMap, "daoUrl") + entityName + "%s"), key);
                            } else if (VUE.equals(key)) {
                                fileName = String.format((getConfigBuilder().getGlobalConfig().getOutputDir() + "vue/" + StrUtil.toSymbolCase(tableInfo.getEntityName(), '-') + "%s"), key);
                            } else if (VUE_JS.equals(key)) {
                                fileName = String.format((getConfigBuilder().getGlobalConfig().getOutputDir() + "vue/" + StrUtil.toSymbolCase(tableInfo.getEntityName(), '-') + "%s"), key);
                            }
                            outputFile(new File(fileName), objectMap, value, getConfigBuilder().getInjectionConfig().isFileOverride());
                        });
                    }
                })
                .injectionConfig(builder -> {
                    Map<String, Object> customMap = buildCustomMap(generModel, packageModel);
                    Map<String, String> customFile = buildCustomFile();
                    builder.customMap(customMap)
                            .customFile(customFile)
                            .fileOverride();
                })
                .execute();
    }

    /**
     * 构建自定义模板文件
     *
     * @return
     */
    @NotNull
    private static Map<String, String> buildCustomFile() {
        Map<String, String> customFile = MapUtil.newHashMap();
        customFile.put(CREATE_IN_VO, "/dto/create-in.java.ftl");
        customFile.put(UPDATE_IN_VO, "/dto/update-in.java.ftl");
        customFile.put(SEARCH_IN_VO, "/dto/search-in.java.ftl");
        customFile.put(LIST_OUT_VO, "/dto/list-out.java.ftl");
        customFile.put(CONVERT, "/dto/convert.java.ftl");
        customFile.put(DAO, "/simple/dao.java.ftl");
        customFile.put(VUE, "/vue/manage-element.vue.ftl");
        customFile.put(VUE_JS, "/vue/vue.js.ftl");
        return customFile;
    }

    /**
     * 构建自定义变量
     *
     * @param generModel
     * @param packageModel
     * @return
     */
    @NotNull
    private static Map<String, Object> buildCustomMap(GenerModel generModel, PackageModel packageModel) {
        final String inputDtoPack = StrUtil.builder().append(packageModel.getParent()).append(StringPool.DOT).append(packageModel.getInputDto()).toString();
        final String outDtoPack = StrUtil.builder().append(packageModel.getParent()).append(StringPool.DOT).append(packageModel.getOutDto()).toString();
        final String dtoMapperDtoPack = StrUtil.builder().append(packageModel.getParent()).append(StringPool.DOT).append(packageModel.getDtoMapper()).toString();
        final String daoMapperDtoPack = StrUtil.builder().append(packageModel.getParent()).append(StringPool.DOT).append(packageModel.getDao()).toString();

        final String inputDtoUrl = StrUtil.builder().append(generModel.getPack()).append(StrUtil.replace(inputDtoPack, StringPool.DOT, StringPool.SLASH)).append(StringPool.SLASH).toString();
        final String outputDtoUrl = StrUtil.builder().append(generModel.getPack()).append(StrUtil.replace(outDtoPack, StringPool.DOT, StringPool.SLASH)).append(StringPool.SLASH).toString();
        final String dtoMapperUrl = StrUtil.builder().append(generModel.getPack()).append(StrUtil.replace(dtoMapperDtoPack, StringPool.DOT, StringPool.SLASH)).append(StringPool.SLASH).toString();
        final String daoUrl = StrUtil.builder().append(generModel.getPack()).append(StrUtil.replace(daoMapperDtoPack, StringPool.DOT, StringPool.SLASH)).append(StringPool.SLASH).toString();


        Map<String, Object> customMap = MapUtil.newHashMap();
        customMap.put("inputDtoPackage", packageModel.getParent() + StringPool.DOT + packageModel.getInputDto());
        customMap.put("outputDtoPackage", packageModel.getParent() + StringPool.DOT + packageModel.getOutDto());
        customMap.put("dtoMapperPackage", packageModel.getParent() + StringPool.DOT + packageModel.getDtoMapper());
        customMap.put("daoPackage", packageModel.getParent() + StringPool.DOT + packageModel.getDao());
        customMap.put("inputDtoUrl", inputDtoUrl);
        customMap.put("outputDtoUrl", outputDtoUrl);
        customMap.put("dtoMapperUrl", dtoMapperUrl);
        customMap.put("daoUrl", daoUrl);
        return customMap;
    }

}
